
#include "LevelManager.h"
#include "hRandom.h"
#include "hMath.h"
#include "TextureManager.h"
#include "ScoreManager.h"
#include "ProgressManager.h"
#include "InputManager.h"
#include "Painter.h"
#include "Baby.h"
#include "SB.h"
#include "ParticleManager.h"
#include <libXml/tree.h>
#include "XMLController.h"
#include "AudioUtils.h"
#include "ScaleEffect.h"
#include "FadeEffect.h"
#include "MoveEffect.h"
#include "PowerupData.h"
#include "BackgroundManager.h"

const float FED_BABY_FAIL_TIME = -1.5f;
const float FED_BABY_SUCCESS_TIME = 2.8f;
const float DISCARD_FOOD_FAIL_TIME = -1.0f;
const float DISCARD_FOOD_SUCCESS_TIME = 2.0f;

const float START_POWER_UP_TIME = 2.2f;

const int DISCARD_FOOD_HEARTS = 50;

LevelManager::~LevelManager()
{
	BabiesVector::iterator it = babies.begin();
	while(it != babies.end())
	{
		delete (*it);
		++it;
	}
	babies.clear();
	
	FoodVector::iterator it2 = foods.begin();
	while(it2 != foods.end())
	{
		delete (*it2);
		++it2;
	}
	foods.clear();
    
    PrizeVector::iterator it3 = prizes.begin();
	while(it3 != prizes.end())
	{
		delete (*it3);
		++it3;
	}
	prizes.clear();
    
    delete m_oTextReady;
    delete m_oTextFeed;
    delete m_oFoodTrail;
    //Create cloud
    delete m_aoClouds[0];
    delete m_aoClouds[1];
    delete m_aoClouds[2];
    delete m_aoClouds[3];
    
    delete m_aoShadows[0];
    delete m_aoShadows[1];
    delete m_aoShadows[2];
    delete m_aoShadows[3];
    
    delete m_oExtraRainbowButton;
    delete m_oExtraRainbowNumber;
    delete m_oDoubleCoins;
    delete m_oDoubleCoinsNumber;
    delete m_oChainBoost;
    delete m_oChainBoostNumber;
    delete m_oSuperChainBoost;
    delete m_oSuperChainBoostNumber;
    delete m_oPrizeSeason;
    delete m_oPrizeSeasonNumber;
}

void LevelManager::init()
{    
    // init particles
    ParticleManager::instance().initialize();
    ParticleManager::instance().loadXML();
    
    readBabiesAndFoodsXML();
    
    m_oTextReady = new TextEntity("READY", FONT_NAME, 128, Vector2(320.0f, 480.0f), 1, 1);
    m_oTextReady->setColor(COLOR_WHITE);
    m_oTextReady->setAlpha(0);
    m_oTextReady->setCentered();
    m_oTextReady->setShadow();
    
    m_oTextFeed = new TextEntity( "FEED!", FONT_NAME, 128, Vector2(320.0f, 480.0f), 1, 1);
    m_oTextFeed->setColor(COLOR_WHITE);
    m_oTextFeed->setAlpha(0);
    m_oTextFeed->setCentered();
    m_oTextFeed->setShadow();
     
    m_oReadyShow = new TimeLineEffect();
    m_oReadyShow->addEffect(new FadeEffect(m_oTextReady, 0.2, false, false, 0, 1), 0);
    m_oReadyShow->addEffect(new ScaleEffect(m_oTextReady, 1.0, false, false, Vector2(0.5, 0.5), Vector2(1, 1)), 0);
    m_oReadyShow->addEffect(new FadeEffect(m_oTextReady, 0.2, false, false, 1, 0), 0.8);

    m_oFeedShow = new TimeLineEffect();
    m_oFeedShow->addEffect(new FadeEffect(m_oTextFeed, 0.2, false, false, 0, 1), 0);
    m_oFeedShow->addEffect(new ScaleEffect(m_oTextFeed, 0.2, false, false, Vector2(0.5, 0.5), Vector2(1.1, 1.1)), 0);
    m_oFeedShow->addEffect(new ScaleEffect(m_oTextFeed, 0.05, false, false, Vector2(1, 1)), 0.2);
    m_oFeedShow->addEffect(new FadeEffect(m_oTextFeed, 0.2, false, false, 1, 0), 1.0);

    m_oFoodTrail = ParticleManager::instance().addParticles( "foodTrail", Vector3(0.0f, 0.0f, 0.0f));
    m_oFoodTrail->m_bRender = false;
    m_oFoodTrail->m_bStopSpawning = true;
    
    m_iFingerTrailIndex = 0;
    for(int i=0; i<FINGER_TRAIL_COUNT; ++i)
    {
        m_asFingerTrail[i].m_oIcon = new RenderableEntity("fx4", Vector2(0.0f, 0.0f));
        m_asFingerTrail[i].m_oIcon->setScale(Vector2(0.50f, 0.50f));
        m_asFingerTrail[i].m_fTime = -10;
    }

    m_oFedSuccesParticles = ParticleManager::instance().addParticles( "fedSuccess", Vector3(0.0f, 0.0f, 0.0f));
    m_oFedSuccesParticles->m_bRender = false;
    m_oFedSuccesParticles->m_bStopSpawning = true;
    
    m_oExtraRainbowButton = new RenderableEntity("extraRainbow", Vector2(320.0f, 300.0f));
    m_oExtraRainbowButton->setCentered();
    m_oExtraRainbowNumber = new TextEntity("1", FONT_NAME, 45, Vector2(390.0f, 270.0f), 1, 1);
    m_oExtraRainbowNumber->setCentered();
    
    m_oBulletTime = new RenderableEntity("boletTime", Vector2(100.0f, 100.0f));
    m_oBulletTime->setCentered();
    m_oBulletTime->setScale(Vector2(0.7f, 0.7f));
    m_oBulletTimeNumber = new TextEntity("1", FONT_NAME, 45, Vector2(150.0f, 90.0f), 1, 1);
    m_oBulletTimeNumber->setCentered();
    
    m_oDoubleCoins = new RenderableEntity("doubleCoins", Vector2(80.0f, 270.0f));
    m_oDoubleCoins->setCentered();
    m_oDoubleCoins->setScale(Vector2(0.7f, 0.7f));
    m_oDoubleCoinsNumber = new TextEntity("1", FONT_NAME, 45, Vector2(130.0f, 260.0f), 1, 1);
    m_oDoubleCoinsNumber->setCentered();
    
    m_oChainBoost = new RenderableEntity("chainBoost", Vector2(190.0f, 400.0f));
    m_oChainBoost->setCentered();
    m_oChainBoost->setScale(Vector2(0.7f, 0.7f));
    m_oChainBoostNumber = new TextEntity("1", FONT_NAME, 45, Vector2(240.0f, 390.0f), 1, 1);
    m_oChainBoostNumber->setCentered();
    
    m_oSuperChainBoost = new RenderableEntity("megaChainBoost", Vector2(300.0f, 270.0f));
    m_oSuperChainBoost->setCentered();
    m_oSuperChainBoost->setScale(Vector2(0.7f, 0.7f));
    m_oSuperChainBoostNumber = new TextEntity("1", FONT_NAME, 45, Vector2(350.0f, 260.0f), 1, 1);
    m_oSuperChainBoostNumber->setCentered();
    
    m_oPrizeSeason = new RenderableEntity("prizeSeason", Vector2(410.0f, 400.0f));
    m_oPrizeSeason->setCentered();
    m_oPrizeSeason->setScale(Vector2(0.7f, 0.7f));
    m_oPrizeSeasonNumber = new TextEntity("1", FONT_NAME, 45, Vector2(460.0f, 390.0f), 1, 1);
    m_oPrizeSeasonNumber->setCentered();
    
    m_oTutorialArrow = new RenderableEntity("arrowtut", Vector2(100.0f, 100.0f));
    m_oTutorialArrow->setCentered();
    m_oTutorialArrow->setColor(Vector4(1.0f, 1.0f, 1.0f, 0.0f));
    
    BackgroundManager::instance().initNew();
    
    // load clouds
    //Create cloud
    m_aoClouds[0] = new AnimatedEntity("cloud_baby", Vector2(0,0));
    m_aoClouds[0]->setScale(Vector2(1.5f, 1.5f));
    m_aoClouds[1] = new AnimatedEntity("cloud_baby", Vector2(0,0));
    m_aoClouds[1]->setScale(Vector2(1.5f, 1.5f));
    m_aoClouds[2] = new AnimatedEntity("cloud_baby", Vector2(0,0));
    m_aoClouds[2]->setScale(Vector2(1.5f, 1.5f));
    m_aoClouds[3] = new AnimatedEntity("cloud_baby", Vector2(0,0));
    m_aoClouds[3]->setScale(Vector2(1.5f, 1.5f));
    
    m_aoShadows[0] = new RenderableEntity("shadow2", Vector2(0,0));
    m_aoShadows[0]->setScale(Vector2(0.7f, 1.0f));
    m_aoShadows[0]->setCentered();
    m_aoShadows[1] = new RenderableEntity("shadow2", Vector2(0,0));
    m_aoShadows[1]->setScale(Vector2(0.7f, 1.0f));
    m_aoShadows[1]->setCentered();
    m_aoShadows[2] = new RenderableEntity("shadow2", Vector2(0,0));
    m_aoShadows[2]->setScale(Vector2(0.7f, 1.0f));
    m_aoShadows[2]->setCentered();
    m_aoShadows[3] = new RenderableEntity("shadow2", Vector2(0,0));
    m_aoShadows[3]->setScale(Vector2(0.7f, 1.0f));
    m_aoShadows[3]->setCentered();
}

void LevelManager::reset()
{
    BabiesVector::iterator it = babies.begin();
	while ( it!= babies.end() )
	{
        Baby* baby = (Baby*)(*it);
        delete baby;
        ++it;
	}
    babies.clear();
    
    FoodVector::iterator itFood = foods.begin();
    while ( itFood!= foods.end() )
    {
        Food* food = (Food*)(*itFood);
        delete food;
        ++itFood;
    }
    foods.clear();
    
    PrizeVector::iterator it3 = prizes.begin();
	while(it3 != prizes.end())
	{
		delete (*it3);
		++it3;
	}
	prizes.clear();
    
    BabiesDataMap::iterator it4 = m_moBabiesData.begin();
	while ( it4!= m_moBabiesData.end() )
	{
        it4->second.bAvailable = false;
		++it4;
	}    
}

extern "C" const char* getFilePath(const char* fileName);
void LevelManager::readBabiesAndFoodsXML()
{
    m_moBabiesData.clear();
    m_moPrizesData.clear();
    m_vsAllBabiesNamesInOrder.clear();
    
    m_fDiscardProbability = 0.1f;
    
    xmlDocPtr doc = NULL;
    std::string fileName = "/babiesAndFoods.xml";
    std::string fullName = getFilePath(fileName.c_str());
    doc = xmlReadFile(fullName.c_str(), "UTF8", 0);
	if (doc == NULL) {
		return;
	}
	xmlNode *root = NULL;
	root = xmlDocGetRootElement(doc);
        
    int iBabyCount = 0;
    
    //Babies
    xmlNode* nodeBaby = root->children;
    while(nodeBaby)
    {
        if(nodeBaby->type != XML_ELEMENT_NODE)
        {
            nodeBaby = nodeBaby->next;
            continue;
        }

        std::string sBaby = (const char*) xmlGetProp(nodeBaby, (xmlChar*)"name");
        m_vsAllBabiesNamesInOrder.push_back(sBaby);
        m_moBabiesData[sBaby].iIndex = iBabyCount;
        m_moBabiesData[sBaby].sName = sBaby;
        m_moBabiesData[sBaby].sCaption = (const char*) xmlGetProp(nodeBaby, (xmlChar*)"caption");
        XMLController::parseVector2((const char*) xmlGetProp(nodeBaby, (xmlChar*)"mouthOffset"), m_moBabiesData[sBaby].vMouthOffset);
        m_moBabiesData[sBaby].iScore = atoi((const char*) xmlGetProp(nodeBaby, (xmlChar*)"score"));
        XMLController::parseVector4((const char*) xmlGetProp(nodeBaby, (xmlChar*)"color"), m_moBabiesData[sBaby].vColor);
        m_moBabiesData[sBaby].iPrice = atoi((const char*) xmlGetProp(nodeBaby, (xmlChar*)"price"));
        XMLController::parseVector5((const char*) xmlGetProp(nodeBaby, (xmlChar*)"levelUp"), m_moBabiesData[sBaby].iLevelUpPrice);
        
        float f = 1.0f/255.0f;
        m_moBabiesData[sBaby].vColor *= f;
        
        Baby* loadImagesBaby = new Baby(sBaby, (eBabyPos) 0, 0);
        delete loadImagesBaby;
        
        //Foods
        xmlNode* node = nodeBaby->children;
        while(node)
        {
            if(node->type != XML_ELEMENT_NODE)
            {
                node = node->next;
                continue;
            }
            
            if(strncmp((const char*) node->name, "food", 4) == 0)
            {
                m_moBabiesData[sBaby].sFood = (const char*) xmlGetProp(node, (xmlChar*)"name");
                m_moBabiesData[sBaby].bFoodAnimated = strncmp((const char*) xmlGetProp(node, (xmlChar*)"animated"), "true", 4) == 0;
            }
            else if (strncmp((const char*) node->name, "priz", 4) == 0)
            {
                PrizeData prizeData;
                std::string sPrize = (const char*) xmlGetProp(node, (xmlChar*)"name");
                m_moBabiesData[sBaby].sPrize = sPrize;
                prizeData.fSpawnProbability = atof((const char*) xmlGetProp(node, (xmlChar*)"spawnProbability"));
                prizeData.iScore = atoi((const char*) xmlGetProp(node, (xmlChar*)"score"));
                m_moPrizesData[sPrize] = prizeData;
                
                Prize* loadImagesPrize = new Prize(sPrize, Vector2(0,0));
                delete loadImagesPrize;
            }
            node = node->next;
        }
        
        m_asBabyData[iBabyCount] = m_moBabiesData[sBaby];

        nodeBaby = nodeBaby->next;
        iBabyCount++;
    }
    
    m_iTotalBabies = iBabyCount;
    
	xmlFreeDoc(doc);
}

int LevelManager::getNextActiveBabyNotAvailable()
{
    int iAvailableBabiesInPlay = 0;
    for(int i=0; i<16; ++i)
    {
        if (ProgressManager::instance().getSavedData().sBabyData[i].bUnlocked)
        {
            ++iAvailableBabiesInPlay;
            if (iAvailableBabiesInPlay > m_iAvailableBabies)
            {
                return i;
            }
        }
    }
    return -1;
}

void LevelManager::initAvailableBabies()
{
    m_iAvailableBabies = 0;
    m_vecsAvailableBabies.clear();
    
    int iIndex;
    std::string sName;
    
    for(int i=0; i<7; ++i)
    {
        iIndex = getNextActiveBabyNotAvailable();
        sName = getBabyName(iIndex);
        m_vecsAvailableBabies.push_back(sName);
        m_moBabiesData[sName].bAvailable = true;
        ++m_iAvailableBabies;
    }
}

void LevelManager::updateAvailableBabies()
{
    if( m_iScore > m_iScoreToUnlockNewBaby)
    {
        m_iScoreToUnlockNewBaby += 3;
        ++m_iAvailableBabies;
        m_iNextBabyIndex = getNextActiveBabyNotAvailable();
        if (m_iNextBabyIndex != -1)
        {
            std::string sName = getBabyName(m_iNextBabyIndex);
            m_vecsAvailableBabies.push_back(sName);
            m_moBabiesData[sName].bAvailable = true;
        }
    }
}

float LevelManager::getChainMultiplier()
{
    if (m_iScoreInARow > 10)
    {
        return CHAIN_MULTIPLIER * 10;
    }
    return CHAIN_MULTIPLIER * m_iScoreInARow; 
}

void LevelManager::startCountdown()
{
    BackgroundManager::instance().restartVars();
    m_fLastAlpha = 0.0f;
    m_iCorrectDiscarded = 0;
    m_iRounds = 1;
    reset();
    ScoreManager::instance().startGame();
    ScoreManager::instance().initRainbow(MAX_BAR_TIME);
    gameState = Countdown;
    m_fStateTimer = 0.0f;
    m_iHearts = 0;
    m_iScore = 0;
    m_iScoreInARow = 0;
    m_fTime = MAX_BAR_TIME;
	//UserManager::instance().fillUserData( scoreData );
    m_fGameSpeed = 1.1f;
    m_iScoreToUnlockNewBaby = 10;
    m_fBulletTimeLeft = 0.0f;
    m_fNoRainbowTimer = 0.0f;
    
    m_iSpecialRound = OneBaby;
    m_bStartNormalAfterSpecial = false;
    m_fAfterSpecialTimer = 0.0f;
    m_bBigBabyShown = false;
    m_bThreeBabiesShown = false;
    
    m_bClickOutOfPowerUps = false;
    m_bRainbowUsed = false;
    m_bBulletTimeUsed = false;
    m_bDoubleCoinsUsed = false;
    m_bChainBoostUsed = false;
    m_bSuperChainBoostUsed = false;
    m_bPrizeSeasonUsed = false;

/*    
    // set the number for power ups
    char tiChar2[2];
    sprintf(tiChar2, "%d", ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_EXTRA_RAINBOW]);
    m_oExtraRainbowNumber->setText(tiChar2);
    char tiChar3[2];
    sprintf(tiChar3, "%d", ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_BOLET_TIME]);
    m_oBulletTimeNumber->setText(tiChar3);
    char tiChar4[2];
    sprintf(tiChar4, "%d", ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_CHAIN_BOOST]);
    m_oChainBoostNumber->setText(tiChar4);
    char tiChar5[2];
    sprintf(tiChar5, "%d", ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_SUPER_CHAIN_BOOST]);
    m_oSuperChainBoostNumber->setText(tiChar5);
    char tiChar6[2];
    sprintf(tiChar6, "%d", ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_DOUBLE_COINS]);
    m_oDoubleCoinsNumber->setText(tiChar6);
    char tiChar7[2];
    sprintf(tiChar7, "%d", ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_PRIZE_SEASON]);
    m_oPrizeSeasonNumber->setText(tiChar7);
*/
    
    // init the available babies vector
    initAvailableBabies();
    
    m_oReadyShow->start(true);
}

/*
void LevelManager::useBulletTime()
{
    m_fBulletTimeLeft = 10.0f;
    m_bBulletTimeUsed = true;
    
    ProgressManager::instance().substractPowerUp(POWERUP_BOLET_TIME);
}

void LevelManager::useExtraRainbow()
{
    gameState = Countdown;
    ScoreManager::instance().initRainbow(MAX_BAR_TIME);
    m_fStateTimer = 0.0f;
    m_fTime = MAX_BAR_TIME;
    m_bRainbowUsed = true;
    
    ProgressManager::instance().substractPowerUp(POWERUP_EXTRA_RAINBOW);
}
*/

void LevelManager::startGame(bool _bExtraRainbow)
{
	gameState = Normal;
    m_fStateTimer = 0.0f;
    LevelManager::instance().setNextBabyType(BabyLeft);
    spawnBaby(BabyLeft, 0);
    LevelManager::instance().setNextBabyType(BabyCenter);
    spawnBaby(BabyCenter, 1);
    LevelManager::instance().setNextBabyType(BabyRight);
    spawnBaby(BabyRight, 2);
    m_iFreeCloud = 3;
    
    spawnFood();
    
    m_fTime = INITIAL_TIME;
    m_oFeedShow->start(true);
}

void LevelManager::gameOver()
{
    gameState = GameOver;
    ProgressManager::instance().gameCompleted(m_iScore, m_iHearts, m_iPrizeCount, m_iMaxCombo);
}

void LevelManager::updateEndGame()
{
//    if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_EXTRA_RAINBOW] > 0 && !m_bRainbowUsed)
    if(false)
    {
        if (m_fNoRainbowTimer > 2.0f)
        {
            gameOver();
        }
        else
        {
            if (m_oExtraRainbowButton->isClicked())
            {
                useExtraRainbow();
            }
        }
    }
    else
    {
        if (m_fNoRainbowTimer > 1.0f)
        {
            gameOver();
        }
    }
}

void LevelManager::updateCountdown()
{
    if (m_fStateTimer > 1.0f)
    {
        startGame(false);
    }
}

void LevelManager::makeFoodAndBabiesDisappear()
{
    babies[0]->disappear();
    babies[0]->setBabySpawnedBaby(true);
    babies[1]->disappear();
    babies[1]->setBabySpawnedBaby(true);
    babies[2]->disappear();
    babies[2]->setBabySpawnedBaby(true);
    FoodVector::iterator it = foods.begin();
    while ( it!= foods.end() )
    {
        (*it)->disappear();
        (*it)->setSpawnedFood(true);
        ++it;
    }
}

void LevelManager::startSpecialRound(int _iRoundType)
{
    switch(_iRoundType)
    {
        case ThreeBabies:
        {
            std::string sBaby = getBabyName( m_aiCurrentBabyIndexes[0] );
            Food* food = new Food(getFoodFromBaby(sBaby));
            food->setMultiFood(true, 2);
            foods.push_back(food);
            sBaby = getBabyName( m_aiCurrentBabyIndexes[1] );
            Food* food2 = new Food(getFoodFromBaby(sBaby));
            food2->setMultiFood(true, 0);
            foods.push_back(food2);
            sBaby = getBabyName( m_aiCurrentBabyIndexes[2] );
            Food* food3 = new Food(getFoodFromBaby(sBaby));
            food3->setMultiFood(true, 1);
            foods.push_back(food3);
            break;
        }
        case BigBaby:
            break;
    }
    
    m_iSpecialRound = _iRoundType;
}

void LevelManager::checkSpecialStates()
{
    /*if (!m_bThreeBabiesShown && m_iRounds % 3 == 0)
    {
        m_bThreeBabiesShown = true;
        startSpecialRound(ThreeBabies);
    }*/
}

void LevelManager::updateTutorials()
{
    eBabyPos ePos = BabyDiscard;
    if (foods.size() == 0) return;
    
    if (babyAndFoodMatch(getBabyInPos(BabyLeft)->getEntityName(), foods[0]->getEntityName()))
    {
        ePos = BabyLeft;
    }
    else if (babyAndFoodMatch(getBabyInPos(BabyCenter)->getEntityName(), foods[0]->getEntityName()))
    {
        ePos = BabyCenter;
    }
    else if (babyAndFoodMatch(getBabyInPos(BabyRight)->getEntityName(), foods[0]->getEntityName()))
    {
        ePos = BabyRight;
    }
    
    float timer = foods[0]->getTimeInWaitingState();
    if (timer == -1.0f)
    {
        m_fLastAlpha -= SB::dt * 2;
        m_oTutorialArrow->setColor(Vector4(1.0f,1.0f,1.0f, m_fLastAlpha));
    }
    else
    {
        // set the arrow orientated
        m_oTutorialArrow->setPosition(Vector2(320.0f, 230.0f));
        m_oTutorialArrow->setScale(Vector2(1.0f, 1.0f));
        if (ePos == BabyLeft)
        {
            m_oTutorialArrow->setRotation(0.61f);
        }
        else if (ePos == BabyCenter)
        {
            m_oTutorialArrow->setRotation(0.0f);            
        }
        else if (ePos == BabyRight)
        {
            m_oTutorialArrow->setRotation(-0.61f);            
        }
        else // if it is to discard
        {
            m_oTutorialArrow->setRotation(3.14f);
        }

        float fAlpha;
        if ((m_iScore > 2 && ePos != BabyDiscard) || (m_iCorrectDiscarded > 0 && ePos == BabyDiscard))
        {
            fAlpha = 0;
        }
        else
        {
            fAlpha = fmodf(timer, 1);
            if (fAlpha > 0.5f)
            {
                fAlpha = 1.0f - fAlpha;
            }
        }
            
        m_oTutorialArrow->setColor(Vector4(1.0f,1.0f,1.0f, fAlpha));
        
        m_fLastAlpha = fAlpha;
    }
}

// UPDATE
void LevelManager::update(float dt)
{
    m_fStateTimer += dt;
    
    if (m_bStartNormalAfterSpecial)
    {
        m_fAfterSpecialTimer -= SB::dt;
        if (m_fAfterSpecialTimer < 0.0f)
        {
            m_bStartNormalAfterSpecial = false;
            startNormalRoundAfterSpecial();
        }
    }
    else if (m_iSpecialRound == ThreeBabies)
    {
        m_fSpecialTimer += SB::dt;
        if (m_fSpecialTimer > 1.0f && m_fSpecialTimer < 2.5f)
        {
            SB::dt = dt * 0.1f;
        }
        if (m_iEndSpecialRound == 3)
        {
            prepareNormalRoundAfterSpecial();
            m_iEndSpecialRound = 0;
        }
    }
    else
    {
        m_fBulletTimeLeft -= dt;
        if (m_fBulletTimeLeft > 0.0f)
        {
            SB::dt = dt * 0.5f;
        }
    }
    
    for(int i=0; i<FINGER_TRAIL_COUNT; ++i)
    {
        m_asFingerTrail[i].m_fTime -= SB::dt;
    }
    
	if(InputManager::instance().hasJustPressed())
	{
        m_vLastPressedPos = InputManager::instance().getPosition() * 2;
        
        for(int i=0; i<FINGER_TRAIL_COUNT; ++i)
        {
            m_asFingerTrail[i].m_fTime = -10;
        }
	}
	
	if(InputManager::instance().isPressed() || InputManager::instance().hasJustReleased())
	{
        Vector2 vPos = InputManager::instance().getPosition() * 2;
        Vector2 vDir = vPos - m_vLastPressedPos;
        float fDist = vDir.length();
        vDir.normalize();
        float fFactor = 1.0f;
        for(int i=0; i<=fDist * fFactor; ++i)
        {
            m_asFingerTrail[m_iFingerTrailIndex].m_fTime = 0.4f;
            m_asFingerTrail[m_iFingerTrailIndex].m_oIcon->setPosition(m_vLastPressedPos + vDir * i / fFactor);
            m_iFingerTrailIndex = (m_iFingerTrailIndex + 1) % FINGER_TRAIL_COUNT;
        }
        m_vLastPressedPos = vPos;
	}
	    
    switch(gameState)
    {
        case Countdown:
            updateCountdown();            
            break;
            
        case Normal:
            m_bPrizeTookThisFrame = false;
            updatePrizes();
            updateBabies();
            updateFood();
            updateTutorials();
            
            m_fTime -= SB::dt * m_fGameSpeed;
            
            if (ScoreManager::instance().getRainbowProgress() < 0.0f)
            {
                makeFoodAndBabiesDisappear();
                m_fNoRainbowTimer = 0.0f;
                gameState = EndGame;
                m_fBulletTimeLeft = 0.0f;
            }
            
            /*
            if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_BOLET_TIME] > 0 && !m_bBulletTimeUsed)
            {
                if (m_oBulletTime->isClicked())
               {
                    useBulletTime();
               }
            } 
            */
            break;
            
        case EndGame:
            m_fNoRainbowTimer += SB::dt;
            updatePrizes();
            updateBabies();
            updateFood();
            updateEndGame();
            break;
        case GameOver:
            break;
    }
    
    // update the start powerups
    if (m_fStateTimer < START_POWER_UP_TIME && !m_bClickOutOfPowerUps)
    {
        updateStartPowerUps();
    }
    
    ParticleManager::instance().update();
    
    checkSpecialStates();
}

void LevelManager::updateStartPowerUps()
{
    // see if the player first presses in another zone because wants to play without using powerups
    if (InputManager::instance().hasJustPressed() &&
        !m_oDoubleCoins->isPressed() &&
        !m_oChainBoost->isPressed() &&
        !m_oSuperChainBoost->isPressed() &&
        !m_oPrizeSeason->isPressed())
    {
        m_bClickOutOfPowerUps = true;
        return;
    }
    
/*
    if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_DOUBLE_COINS] > 0 && !m_bDoubleCoinsUsed)
    {
        if (m_oDoubleCoins->isClicked())
        {
            m_bDoubleCoinsUsed = true;
            ProgressManager::instance().substractPowerUp(POWERUP_DOUBLE_COINS);
        }
    }
    if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_CHAIN_BOOST] > 0 && !m_bChainBoostUsed && !m_bSuperChainBoostUsed)
    {
        if (m_oChainBoost->isClicked())
        {
            m_bChainBoostUsed = true;
            ProgressManager::instance().substractPowerUp(POWERUP_CHAIN_BOOST);
            m_iScoreInARow = 10;
            ScoreManager::instance().setChainMultiplier(10, true);
        }
    }
    if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_SUPER_CHAIN_BOOST] > 0 && !m_bChainBoostUsed && !m_bSuperChainBoostUsed)
    {
        if (m_oSuperChainBoost->isClicked())
        {
            m_bSuperChainBoostUsed = true;
            ProgressManager::instance().substractPowerUp(POWERUP_SUPER_CHAIN_BOOST);
            m_iScoreInARow = 30;
            ScoreManager::instance().setChainMultiplier(30, true);
        }
    }
    if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_PRIZE_SEASON] > 0 && !m_bPrizeSeasonUsed)
    {
        if (m_oPrizeSeason->isClicked())
        {
            m_bPrizeSeasonUsed = true;
            ProgressManager::instance().substractPowerUp(POWERUP_PRIZE_SEASON);
        }
    }
*/
}

// Babies
Baby* LevelManager::getBabyInPos(eBabyPos _iBabyPos)
{
	BabiesVector::iterator it = babies.begin();
	while ( it!= babies.end() )
	{
        Baby* baby = (Baby*)(*it);
		if( baby->getBabyPos() == _iBabyPos)
			return baby;
		
		++it;
	}
    
    return 0;
}

int LevelManager::getRandomAvailableAnimalIndex()
{
    int iAvailableIndex = hRandom::getRandomInt(0, m_vecsAvailableBabies.size()-1);
    std::string baby = m_vecsAvailableBabies[iAvailableIndex];
    return getBabyIndex(baby);
}

void LevelManager::setNextBabyType(eBabyPos _eBabyPos)
{
    bool bGotBaby = false;
    do
    {
        // get a random baby index among the current available babies
        m_iNextBabyIndex = getRandomAvailableAnimalIndex();
        
        // check that the old animal is different to the new one
        if (babies.size() == 3)
        {
            if (getBabyInPos(_eBabyPos) != NULL)
            {
                std::string lol = m_vsAllBabiesNamesInOrder[m_iNextBabyIndex];
                std::string lal = getBabyInPos(_eBabyPos)->getEntityName();
                //bGotBaby = m_voBabiesRoster[m_iNextBabyIndex].compare(getBabyInPos(_eBabyPos)->getEntityName()) != 0;
                bGotBaby = lol.compare(lal) != 0;
            }
            else
            {
                bGotBaby = false;
            }
        
        
            // check that there won't be 3 babies of the same type
            int iSame = 1;
            for(int i=0; i<3; ++i)
            {
                if (i != _eBabyPos)
                {
                    
                    if (getBabyInPos((eBabyPos)i) != NULL && m_vsAllBabiesNamesInOrder[m_iNextBabyIndex].compare(getBabyInPos((eBabyPos)i)->getEntityName()) == 0)
                    {
                        ++iSame;
                    }
                }
            }
            bGotBaby = bGotBaby && iSame < 3;
        }
        else
        {
            bGotBaby = true;
        }
        
    } while(!bGotBaby);
    
    m_aiCurrentBabyIndexes[_eBabyPos] = m_iNextBabyIndex;
}

void LevelManager::updatePrizes()
{
    if (gameState == EndGame)
    {
        PrizeVector::iterator it = prizes.begin();
        while ( it!= prizes.end() )
        {
            Prize* prize = (Prize*)(*it);
            prize->update();
            prize->setScale(prize->getScale() * 0.9f);
            ++it;
        } 
    }
    else
    {
        PrizeVector::iterator it = prizes.begin();
        while ( it!= prizes.end() )
        {
            Prize* prize = (Prize*)(*it);
            Vector2 test = prize->getPosition();
            if (prize->playerTookIt())
            {          
                AudioUtils::playSfx("FX_Prize.mp3");
                m_bPrizeTookThisFrame = true;
                // add score and delete the object
                std::string sName = prize->getEntityName();
                int iPrizeScore = m_moPrizesData[sName].iScore;
                addHearts(iPrizeScore, prize->getPosition());
                prizes.erase(it);
                delete prize;  
                
                m_iPrizeCount++;
            }
            else
            {
                prize->update();
                ++it;
            }
        }        
    }

}

void LevelManager::spawnBaby(eBabyPos _eBabyPos, int _iCloud)
{
    //int iType = hRandom::getRandomInt(0, MAX_BABY_TYPES - 1);
    Baby* baby = new Baby(m_vsAllBabiesNamesInOrder[m_iNextBabyIndex], _eBabyPos, _iCloud);
//  baby->setScale(Vector2(0.5, 0.5));
    babies.push_back(baby);
}

void LevelManager::updateBabies()
{
	BabiesVector::iterator it = babies.begin();
	while ( it!= babies.end() )
	{
        Baby* baby = (Baby*)(*it);
        if (baby != NULL)
        {
            baby->update();
            
            switch (baby->getBabyState()) {
                case Baby_Exiting:
                    if (!baby->getBabySpawnedBaby() && m_fSpecialTimer < 1.0f)
                    {
                        spawnBaby(baby->getBabyPos(), m_iFreeCloud);
                        baby->setBabySpawnedBaby(true);
                        m_iFreeCloud = baby->getCloudIndex();
                    }
                    ++it;
                    break;
                case Baby_End:
                    it = babies.erase(it);
                    delete baby;
                    break;
                    
                default:
                    ++it;
                    break;
            }
        }
    }
}

void LevelManager::addTime(float _fTimeToAdd)
{
    m_fTime += _fTimeToAdd;
    if (m_fTime > MAX_BAR_TIME)
    {
        m_fTime = MAX_BAR_TIME;
    }
}

std::string LevelManager::getFoodFromBaby(std::string _sBaby)
{
    return m_moBabiesData[_sBaby].sFood;
}


bool LevelManager::babyAndFoodMatch(std::string _sBaby, std::string _sFood)
{
    return m_moBabiesData[_sBaby].sFood == _sFood;
}

bool LevelManager::isBabyInGame(std::string _sBaby)
{
    return babies[0]->getEntityName() == _sBaby
    || babies[1]->getEntityName() == _sBaby
    || babies[2]->getEntityName() == _sBaby;
    
}

std::string LevelManager::getAvailableBabyNotInGame()
{
    int iBabies = m_vecsAvailableBabies.size();
    int iBabyIndex = hRandom::getRandomInt(0, iBabies - 1);
    
    std::string sBaby;
    do
    {
        if (iBabyIndex >= iBabies) iBabyIndex = 0;
        
        sBaby = m_vecsAvailableBabies[iBabyIndex];
        ++iBabyIndex;
    }
    while (isBabyInGame(sBaby));
    
    return sBaby;
}

int LevelManager::getIndexOfBabyInRoster(std::string _sBaby)
{
    for(int i=0; i<m_iTotalBabies; ++i)
    {
        if (m_vsAllBabiesNamesInOrder[i].compare(_sBaby) == 0)
            return i;
    }
    return -1;
}

// Food
void LevelManager::spawnFood()
{
    bool bSpawnUndiscardableFood = true;
    // if discard is enabled, see if we need to spawn a discardable type of food
    if (m_bDiscardEnabled && m_iScore > 4)
    {
        bSpawnUndiscardableFood = hRandom::getRandom() > m_fDiscardProbability;
    }
    
    std::string sFood, sBaby;
    if (bSpawnUndiscardableFood)
    {
        // get the baby who will be able to eat the new food
        int iBaby = hRandom::getRandomInt(0, 2);
        
        sBaby = m_vsAllBabiesNamesInOrder[m_aiCurrentBabyIndexes[iBaby]];
        sFood = m_moBabiesData[sBaby].sFood;
    }
    else
    {
        // get a baby that is not in game
        sBaby = getAvailableBabyNotInGame();
        
        // get the food for that baby
        sFood = getFoodFromBaby(sBaby);
    }

    Food* food = new Food(sFood);
    foods.push_back(food);
}

void LevelManager::startNormalRoundAfterSpecial()
{
    LevelManager::instance().setNextBabyType(BabyLeft);
    spawnBaby(BabyLeft, 0);
    LevelManager::instance().setNextBabyType(BabyCenter);
    spawnBaby(BabyCenter, 1);
    LevelManager::instance().setNextBabyType(BabyRight);
    spawnBaby(BabyRight, 2);
    
    spawnFood();
    
    m_fSpecialTimer = 0.0f;
    m_iSpecialRound = OneBaby;
    m_bThreeBabiesShown = false;
}

void LevelManager::prepareNormalRoundAfterSpecial()
{
    switch(m_iSpecialRound)
    {
        case ThreeBabies:
            babies[0]->tryDisappear();
            babies[1]->tryDisappear();
            babies[2]->tryDisappear();
            
            m_fAfterSpecialTimer = 0.8f;
            break;
        case BigBaby:
            m_fAfterSpecialTimer = 0.8f;
            break;
    }
    m_bStartNormalAfterSpecial = true;
}

void LevelManager::updateFood()
{
    // update positions of food
	FoodVector::iterator it = foods.begin();
	while ( it!= foods.end() )
	{
        (*it)->update();
        ++it;
	}
    
    FoodVector::iterator itFood = foods.begin();
    while ( itFood!= foods.end() )
    {
        Food* food = (Food*)(*itFood);
        if(food->getState() == Food_End)
        {
            itFood = foods.erase(itFood);
            if (!food->getSpawnedFood())
            {
                food->setSpawnedFood(true);
                if (m_iSpecialRound == OneBaby)
                {
                    spawnFood();
                }
            }
            delete food;
        }
        else
        {
            ++itFood;
        }
    }
}

void LevelManager::wrongBaby()
{
    m_iScoreInARow = 0;
    ScoreManager::instance().setChainMultiplier(0, false);
}

void LevelManager::correctBaby()
{
    m_iScore++;
    m_iScoreInARow++;
    m_iMaxCombo = fmax(m_iScoreInARow, m_iMaxCombo);
    ScoreManager::instance().setBabies(m_iScore);
    ScoreManager::instance().setChainMultiplier(m_iScoreInARow, false);
}

void LevelManager::addHearts(int _iHearts, Vector2 _vPosition)
{
    if (m_bDoubleCoinsUsed) _iHearts *= 2.0f;
    m_iHearts += _iHearts;
    ScoreManager::instance().setCoins(m_iHearts, _vPosition);
}

void LevelManager::fedCorrectBaby(Baby* _oBaby)
{
    BackgroundManager::instance().updateBGNew();
    
    AudioUtils::playSfx("FX_SuccessComun(score).mp3");
    
    // add particles
    Vector3 vMouthPos = Vector3(_oBaby->getMouthPos().x, _oBaby->getMouthPos().y, 0.0f);
    m_oFedSuccesParticles->position = vMouthPos;
    Vector4 color = m_moBabiesData[_oBaby->getEntityName()].vColor;
    m_oFedSuccesParticles->info.color = m_moBabiesData[_oBaby->getEntityName()].vColor;
    m_oFedSuccesParticles->resetParticles();
    
    // see if the baby spawns a prize
    std::string sPrize = m_moBabiesData[_oBaby->getEntityName()].sPrize;
    if (!sPrize.empty())
    {
        float fPrizeProbability = 0.1f;
        std::string oName = _oBaby->getEntityName();
        
        if (m_bPrizeSeasonUsed) fPrizeProbability += 0.3f;
        
        //float fPrizeProbability = m_moPrizesData[sPrize].fSpawnProbability;
        //fPrizeProbability = 1.0f;
        if (hRandom::getRandom() < fPrizeProbability)
        {
            Prize* oPrize = new Prize(sPrize, _oBaby->getPosition());
            prizes.push_back(oPrize);
        }
    }

    // update score and time
    float fLevelMultiplier = 0.0f;
    std::string oName = _oBaby->getEntityName();

    float fHearts = (float)m_moBabiesData[oName].iScore * (1.0f + getChainMultiplier() + fLevelMultiplier);
    addHearts(fHearts, _oBaby->getPosition());
    addTime(FED_BABY_SUCCESS_TIME * m_fGameSpeed);
    correctBaby();
    
    // increase the game speed
    if (m_iScore < 5)
    {
        m_fGameSpeed += 0.01f;
    }
    else if (m_iScore < 20)
    {
        m_fGameSpeed += 0.03f;
    }
    else if (m_iScore < 40)
    {
        m_fGameSpeed += 0.02f;
    }
    else if (m_iScore < 80)
    {
        m_fGameSpeed += 0.01f;
    }
    else
    {
        m_fGameSpeed += 0.001f;
    }
}

void LevelManager::fedWrongBaby(Baby* _oBaby)
{
    wrongBaby();
    
    if (m_iScore < 6)
    {
        addTime(FED_BABY_FAIL_TIME * m_fGameSpeed * 0.1f);
    }
    else if (m_iScore < 15)
    {
        addTime(FED_BABY_FAIL_TIME * m_fGameSpeed * 0.6f);
    }
    else
    {
        addTime(FED_BABY_FAIL_TIME * m_fGameSpeed);
    }
}

void LevelManager::discardedFood(std::string _sFood)
{
    bool bFound = false;
   	BabiesVector::iterator itBaby = babies.begin();
	while(itBaby != babies.end())
	{
        Baby* bBaby = (*itBaby);
        if( m_moBabiesData[bBaby->getEntityName()].sFood == _sFood)
        {
            wrongBaby();
            addTime(DISCARD_FOOD_FAIL_TIME * m_fGameSpeed);
            bFound = true;
            break;
        }
        ++itBaby;
	}
    
    if(!bFound)
    {
        m_iCorrectDiscarded++;
        correctBaby();
        // set the hearts directly at the hud position
        addHearts( DISCARD_FOOD_HEARTS * getChainMultiplier(), foods.at(0)->getPosition());
        addTime(DISCARD_FOOD_SUCCESS_TIME * m_fGameSpeed);
    }
}

void LevelManager::foodGone(std::string _sFood)
{
    discardedFood(_sFood);
}

void LevelManager::renderPowerUps()
{
/*
    if (gameState == Normal && ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_BOLET_TIME] > 0 && !m_bBulletTimeUsed)
    {
        m_oBulletTime->render();
        m_oBulletTimeNumber->render();
    }
    if (gameState == EndGame && ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_EXTRA_RAINBOW] > 0 && !m_bRainbowUsed)
    {
        m_oExtraRainbowButton->render();
        m_oExtraRainbowNumber->render();
    }
*/
/*    
    if (m_fStateTimer < START_POWER_UP_TIME && !m_bClickOutOfPowerUps)
    {
        if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_DOUBLE_COINS] > 0 && !m_bDoubleCoinsUsed)
        {
            m_oDoubleCoins->render();
            m_oDoubleCoinsNumber->render();
        }
        if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_CHAIN_BOOST] > 0 && !m_bChainBoostUsed && !m_bSuperChainBoostUsed)
        {
            m_oChainBoost->render();
            m_oChainBoostNumber->render();        
        }
        if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_SUPER_CHAIN_BOOST] > 0 && !m_bChainBoostUsed && !m_bSuperChainBoostUsed)
        {
            m_oSuperChainBoost->render();
            m_oSuperChainBoostNumber->render();
        }
        if (ProgressManager::instance().getSavedData().iaPowerUps[POWERUP_PRIZE_SEASON] > 0 && !m_bPrizeSeasonUsed)
        {
            m_oPrizeSeason->render();
            m_oPrizeSeasonNumber->render();
        }
    }
*/
}

void LevelManager::render()
{
	BabiesVector::iterator itBaby = babies.begin();
	while(itBaby != babies.end())
	{
		(*itBaby)->render();
		++itBaby;
	}
    
	FoodVector::iterator itFood = foods.begin();
	while(itFood != foods.end())
	{
		(*itFood)->render();
		++itFood;
	}
    
    PrizeVector::iterator it3 = prizes.begin();
	while(it3 != prizes.end())
	{
		(*it3)->render();
		++it3;
	}
    
    renderPowerUps();
    
    // render intro texts
    m_oTextReady->render();
    m_oTextFeed->render();

    // render particles
    ParticleManager::instance().render();
    
    // scale and render timebar
    float fTime = m_fTime;
    if (fTime > MAX_BAR_TIME)
    {
        fTime = MAX_BAR_TIME;
    }
    ScoreManager::instance().setBarProgress(fTime / MAX_BAR_TIME);
    
    m_oTutorialArrow->render();
    
    for(int i=0; i<FINGER_TRAIL_COUNT; ++i)
    {
        if(m_asFingerTrail[i].m_fTime > 0.0f)
        {
            m_asFingerTrail[i].m_oIcon->setAlpha(m_asFingerTrail[i].m_fTime * 0.5f);
            m_asFingerTrail[i].m_oIcon->render();
        }
    }
}

BabyData LevelManager::getBabyData(std::string _sName)
{
    return m_moBabiesData[_sName];
}

BabyData LevelManager::getBabyData(int _iIndex)
{
    return m_asBabyData[_iIndex];
}

PrizeData LevelManager::getPrizeData(std::string _sName)
{
    return m_moPrizesData[_sName];
}

std::string LevelManager::getBabyName(int _iIndex)
{
    return m_vsAllBabiesNamesInOrder[_iIndex];
}

int LevelManager::getBabyIndex(std::string _sName)
{
    return m_moBabiesData[_sName].iIndex;
}
